package com.mornd.gulimall.cart.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.mornd.gulimall.apis.product.IProductClient;
import com.mornd.gulimall.apis.product.to.SkuInfoTo;
import com.mornd.gulimall.cart.entity.Cart;
import com.mornd.gulimall.cart.entity.CartItem;
import com.mornd.gulimall.cart.entity.UserInfo;
import com.mornd.gulimall.cart.service.ICartService;
import com.mornd.gulimall.cart.utils.UserHolder;
import com.mornd.gulimall.common.core.exception.ServiceException;
import com.mornd.gulimall.common.core.result.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @author: mornd
 * @dateTime: 2023/8/20 - 7:47
 */

@Slf4j
@Service
public class CartServiceImpl implements ICartService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private IProductClient productClient;
    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    public static final String KEY_PREFIX = "cart:";

    @Override
    public CartItem addToCart(Long skuId, Integer num) {
        BoundHashOperations<String, Object, Object> ops = getOps();
        String sku = (String) ops.get(skuId.toString());
        if (StrUtil.isBlank(sku)) {
            CartItem item = new CartItem();
            // 查询 sku 详情
            CompletableFuture<Void> c1 = CompletableFuture.runAsync(() -> {
                R<SkuInfoTo> r = null;
                try {
                    r = productClient.getSkuInfoById(skuId);
                } catch (Exception e) {
                    log.error(e.getMessage());
                    throw new ServiceException("商品服务调用异常，" + e);
                }

                if (r.isFail() || r.getData() == null) {
                    throw new ServiceException("数据不存在");
                }

                SkuInfoTo skuInfo = r.getData();
                item.setCount(num);
                item.setSkuName(skuInfo.getSkuName());
                item.setImage(skuInfo.getSkuDefaultImg());
                item.setTitle(skuInfo.getSkuTitle());
                item.setSkuId(skuInfo.getSkuId());
                item.setPrice(skuInfo.getPrice());
            }, threadPoolTaskExecutor);

            // 查询 sku attr
            CompletableFuture<Void> c2 = CompletableFuture.runAsync(() -> {
                R<List<String>> r = null;
                try {
                    r = productClient.getSkuSaleStringlist(skuId);
                } catch (Exception e) {
                    throw new ServiceException("商品服务调用异常，" + e);
                }
                if (r.isOk()) {
                    item.setSkuAttr(r.getData());
                }
            }, threadPoolTaskExecutor);

            CompletableFuture.allOf(c1, c2).join();

            String json = JSON.toJSONString(item);
            ops.put(skuId.toString(), json);

            return item;
        } else {
            CartItem item2 = JSON.parseObject(sku, CartItem.class);
            item2.setCount(item2.getCount() + num);
            ops.put(skuId.toString(), JSON.toJSONString(item2));

            return item2;
        }
    }

    private BoundHashOperations<String, Object, Object> getOps() {
        UserInfo user = UserHolder.getUser();
        String cartKey = KEY_PREFIX + user.getSessionUser().getId();

        BoundHashOperations<String, Object, Object> boundHashOps = stringRedisTemplate.boundHashOps(cartKey);
        return boundHashOps;
    }

    @Override
    public CartItem getCartItem(Long skuId) {
        BoundHashOperations<String, Object, Object> ops = getOps();
        String json = (String) ops.get(skuId.toString());
        CartItem item = JSON.parseObject(json, CartItem.class);
        return item;
    }

    @Override
    public Cart getCart() {
        UserInfo user = UserHolder.getUser();
        Cart cart = new Cart();
        String key = KEY_PREFIX + user.getSessionUser().getId();
        BoundHashOperations<String, Object, Object> ops = stringRedisTemplate.boundHashOps(key);
        List<Object> values = ops.values();
        List<CartItem> items = values.stream().map(i -> JSON.parseObject(i.toString(), CartItem.class)).collect(Collectors.toList());
        cart.setItems(items);
        return cart;
    }

    @Override
    public void clear() {
        String key = KEY_PREFIX + UserHolder.getUser().getSessionUser().getId();
        stringRedisTemplate.delete(key);
    }

    @Override
    public void deleteItem(Long skuId) {
        BoundHashOperations<String, Object, Object> ops = getOps();
        ops.delete(skuId.toString());
    }

    @Override
    public List<CartItem> getCartItems(Long userId) {
        String key = KEY_PREFIX + userId;
        BoundHashOperations<String, Object, Object> ops = stringRedisTemplate.boundHashOps(key);
        List<Object> values = ops.values();
        List<CartItem> items = values.stream().map(i -> {
            CartItem item = JSON.parseObject(i.toString(), CartItem.class);
            Long skuId = item.getSkuId();
            // 更新价格
            R<SkuInfoTo> r = productClient.getSkuInfoById(skuId);
            if (r.isFail()) {
                throw new ServiceException(r.getMsg());
            } else {
                if (r.getData() == null) {
                    item.setUp(false);
                } else {
                    BigDecimal newPrice = r.getData().getPrice();
                    item.setPrice(newPrice);
                }
            }
            return item;
        }).collect(Collectors.toList());
        return items;
    }
}
